using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Diagnostics.Contracts;
using Konst3d.Efficiency.Suite;
using System.Windows.Threading;

// http://bea.stollnitz.com/blog/?p=11
// http://msdn.microsoft.com/en-us/library/ms754152.aspx

namespace Efficiency.Controls
{
	/// <summary>
	/// Interaction logic for Histogram.xaml
	/// </summary>
	public partial class MonitorStatisticHistogram : UserControl
	{
		#region Dependency Properties

		public static DependencyProperty ItemsProperty = DependencyProperty.Register("Items", typeof(IEnumerable<IStatisticDay>), typeof(MonitorStatisticHistogram),
				new FrameworkPropertyMetadata(null, OnItemsChanged));
		
		public static DependencyProperty MonitoringStatisticProperty = DependencyProperty.Register("Statistic", typeof(IMonitoringStatistic), typeof(MonitorStatisticHistogram),
				new FrameworkPropertyMetadata(null, OnMonitoringStatisticChanged));

		public static DependencyProperty StartDateProperty = DependencyProperty.Register("StartDate", typeof(DateTime), typeof(MonitorStatisticHistogram),
				new FrameworkPropertyMetadata(DateTime.Now, OnStartDayChanged));

		public static DependencyProperty EndDateProperty = DependencyProperty.Register("EndDate", typeof(DateTime), typeof(MonitorStatisticHistogram),
				new FrameworkPropertyMetadata(DateTime.Now, OnEndDayChanged));

		public static DependencyProperty AutoRangeProperty = DependencyProperty.Register("AutoRange", typeof(bool), typeof(MonitorStatisticHistogram),
				new FrameworkPropertyMetadata(false, OnAutoRangeChanged));
		
		#endregion // Dependency Properties

		#region Properties

		public IEnumerable<IStatisticDay> Items
		{
			get
			{
				return (IEnumerable<IStatisticDay>)GetValue(ItemsProperty);
			}
			set
			{
				SetValue(ItemsProperty, value);
			}
		}

		public IMonitoringStatistic Statistic
		{
			get
			{
				return (IMonitoringStatistic)GetValue(MonitoringStatisticProperty);
			}
			set
			{
				SetValue(MonitoringStatisticProperty, value);
			}
		}

		public DateTime StartDate
		{
			get
			{
				return (DateTime)GetValue(StartDateProperty);
			}
			set
			{
				SetValue(StartDateProperty, value);
			}
		}

		public DateTime EndDate
		{
			get
			{
				return (DateTime)GetValue(EndDateProperty);
			}
			set
			{
				SetValue(EndDateProperty, value);
			}
		}

		public bool AutoRange
		{
			get
			{
				return (bool)GetValue(AutoRangeProperty);
			}
			set
			{
				SetValue(AutoRangeProperty, value);
			}
		}

		#endregion // Properties

		#region Constructors

		public MonitorStatisticHistogram()
		{
			InitializeComponent();
			_resizeTimer = new DispatcherTimer(new TimeSpan(0, 0, 1), DispatcherPriority.Normal, OnResizeTimer, Dispatcher);
		}

		#endregion // Constructors

		#region Dependency Properties' Handlers

		private static void OnItemsChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
		{
			MonitorStatisticHistogram control = sender as MonitorStatisticHistogram;
			Contract.Assert(control != null);
		}

		private static void OnMonitoringStatisticChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
		{
			MonitorStatisticHistogram control = sender as MonitorStatisticHistogram;
			Contract.Assert(control != null);

			control.UpdateItems();
		}

		private static void OnStartDayChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
		{
			MonitorStatisticHistogram control = sender as MonitorStatisticHistogram;
			Contract.Assert(control != null);

			control.UpdateItems();
		}

		private static void OnEndDayChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
		{
			MonitorStatisticHistogram control = sender as MonitorStatisticHistogram;
			Contract.Assert(control != null);

			control.UpdateItems();
		}

		private static void OnAutoRangeChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
		{
			MonitorStatisticHistogram control = sender as MonitorStatisticHistogram;
			Contract.Assert(control != null);

			control.UpdateItems();
		}

		#endregion // Dependency Properties' Handlers

		#region Private Methods

		private void UpdateItems()
		{
			if (Statistic != null)
			{
				if (!AutoRange)
				{
					Items = Statistic.GetRange(StartDate, EndDate);
				}
				else
				{
					// calculate range based on available width... from *** to today
					// TOFIX: cache start\end and update range only if really changed?

					double available = uiItemsControl.ActualWidth;
					double itemWidth = 5; // TOFIX: shouldn't be hardcoded

					if (available <= 0.001)
					{
						available = uiItemsControl.DesiredSize.Width;
					}

					if (available > 0.001)
					{
						int count = (int)(available / itemWidth);

						var end = DateTime.Now.Date;
						var start = end.AddDays(-count).Date;

						if (Statistic.StartDate > start)
						{
							start = Statistic.StartDate;
						}

						Items = Statistic.GetRange(start, end);
					}
					else
					{
						// assuming we at startup and don't know yet the width, so we should wait until rendered and then update items...
					}
				}
			}
		}

		#endregion // Private Methods

		#region Event Handlers

		private void OnItemsControlSizeChanged(object sender, SizeChangedEventArgs e)
		{
			if (AutoRange)
			{
				if (_resizeTimer.IsEnabled)
				{
					_resizeTimer.Stop();
				}

				_resizeTimer.Start();
			}
		}

		private void OnResizeTimer(object sender, EventArgs args)
		{
			if (AutoRange)
			{
				_resizeTimer.Stop();
				UpdateItems();
			}
		}

		#endregion Event Handlers

		#region Fields

		private DispatcherTimer _resizeTimer;

		#endregion // Fields
	}
}
